﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Collections;

using Noris.Schedule.Support;
using Noris.Schedule.Support.Data;
using Noris.Schedule.Support.Sql;
using Noris.Schedule.Support.DataFace;
using System.Data.SqlTypes;
using System.Data.SqlClient;
using Noris.Schedule.Support.Services;
using Noris.Schedule.Planning.DataFace;

namespace Noris.Schedule.Planning.ProcessData
{
	// CLASS PlanningComponentCls : základní třída pro jednotlivé funkční komponenty plánovacího systému
	/// <summary>
	/// Třída PlanningComponentCls : základní třída pro jednotlivé funkční komponenty plánovacího systému (typu Knihovna dat a funkcí)
	/// </summary>
	public class PlanningComponentCls
	{
		#region KONSTRUKTORY
		/// <summary>
		/// Konstruktor s předáním parametrů
		/// </summary>
		/// <param name="parent"></param>
		public PlanningComponentCls(PlanningComponentCls parent)
		{
			this.Parent = parent;
			// this.PlanningParameters = null;              // Nebudu nulovat, jde o singleton a už může být korektně nastaven !!!
			this._CreateDataInternal();
			this.DataCreate();
		}
		internal virtual PlanningComponentCls Parent { get; set; }
		/// <summary>
		/// Metoda vrátí Parent objekt přetypovaný na požadovaný typ (pokud typově odpovídá).
		/// Pokud neodpovídá, vrátí null.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <returns></returns>
		protected T GetParent<T>() where T : PlanningComponentCls
		{
			if (this.Parent != null && this.Parent is T)
				return (T)this.Parent;
			return null;
		}
		/// <summary>
		/// Vytvoří si interní data
		/// </summary>
		private void _CreateDataInternal()
		{
			this._DataCarrouselDict = new Dictionary<int, DataCarrouselItemCls>();
		}
		#endregion
		#region ZASTARALÉ METODY
		/// <summary>
		/// Metoda určená pro načtení dat z databáze. Volá se explicitně.
		/// V případě požadavku (true) vrátí velikost obsazené paměti
		/// </summary>
		internal virtual long LoadData()
		{
			return LoadData(false);
		}
		/// <summary>
		/// Metoda určená pro načtení dat z databáze. Volá se explicitně.
		/// V případě požadavku (true) vrátí velikost obsazené paměti
		/// </summary>
		internal virtual long LoadData(bool measureMemoryUsage)
		{
			return (long)0;
		}
		#endregion
		#region VIRTUAL METODY
		/// <summary>
		/// Metoda určená pro vytvoření interních datových objektů. 
		/// Je volána pouze jedenkrát za života instance.
		/// Volá se z konstruktoru. Nelze volat zvenku.
		/// </summary>
		protected virtual void DataCreate() { }
		/// <summary> { get; set; }
		/// Současné číslo verze plánu, jejíž data jsou vybrána v instančních proměnných modulu. Po initu je 0. 
		/// Toto číslo nenastavuje karusel, ale měla by jej nastavovat metoda ActivateDataVersion() konkrétního modulu.
		/// </summary>
		internal int CurrentPlanCVersion { get; set; }
		/// <summary>
		/// Metoda pro aktivaci dat dané verze plánu v rámci modulu.
		/// Aktivace nenačítá data !!!
		/// Ani nevytváří prázdné datové struktury.
		/// Při korektním řízení nedochází ke ztrátě dat: 
		/// data jsou načtena z databáze (DataPrepare), 
		/// držena v instančních proměnných modulu,
		/// při přepnutí na jiný plán jsou původní data uložena do karuselu do položky původní verze plánu, 
		/// pak je karusel přetočen (vybere se nová verze dat) 
		/// a z ní jsou převedena data do instančních položek modulu, kde se s nimi pracuje.
		/// </summary>
		/// <param name="planCVersion">Klíč verze plánu, kterou chceme aktivovat.</param>
		internal virtual void ActivateDataVersion(int planCVersion) { }
		/// <summary>
		/// Metoda je volaná na základě požadavku DataPrepare.
		/// Je volána tehdy, když se mají načíst číselníky a data, která jsou podkladem jak pro plánování, 
		/// tak pro načítání uložených dat plánu.
		/// </summary>
		/// <param name="withFixed">Požadavek na načítání i fixních dat, tj. takových, která nejsou závislá na verzi plánu.</param>
		internal virtual void DataPrepare(bool withFixed) { }
		/// <summary>
		/// Metoda je volaná na základě požadavku DataPrepare.
		/// Metodu si volá metoda DataPrepare().
		/// Je volána tehdy, když se načetly data do tabulek, a mají se vytvořit paměťové indexy.
		/// </summary>
		/// <param name="withFixed">Požadavek na indexování i fixních dat, tj. takových, která nejsou závislá na verzi plánu.</param>
		internal virtual void DataIndexing(bool withFixed) { }
		/// <summary>
		/// Metoda je volaná na základě požadavku DataLoad.
		/// Je volána tehdy, když se mají načíst data konkrétního hotového plánu, uložená v databázi.
		/// Nejde tedy o číselníky, ale o dřív uložený plán.
		/// Tato metoda se volá vždy na požadavek LOAD z uživatelského rozhraní.
		/// </summary>
		internal virtual void DataLoad() { }
		/// <summary>
		/// Metoda je volaná na základě požadavku DataSave.
		/// Zajistí uložení svých základních dat do databáze.
		/// </summary>
		internal virtual void DataSave() { }
		/// <summary>
		/// Metoda je volaná při ukončení práce se všemi daty (ukončení aplikace, odpojení od databázového profilu).
		/// Zajistí uvolnění všech dat z paměti a nulování datových objektů (nikoli modulů !)
		/// Může následovat akce ActivateDataVersion() pro jinou databázi, takže objekty mají být funkční !
		/// POZOR: tato metoda je jediná, která obsahuje defaultní funkcionalitu.
		/// Provede CarrouselClear() a DataCreate().
		/// Při override uvažujme, zda volat base() a provést uvedené, nebo provést něco jiného místo toho anebo něco navíc.
		/// </summary>
		internal virtual void DataClearAll()
		{
			CarrouselClear();              // Smaže data z karuselu
			DataCreate();                  // Smaže (= vytvoří nové prázdné =) instanční datové objekty
		}
		#endregion
		#region KARUSEL
		/// <summary> { get; }
		/// Aktuálně vybraná položka karuselu = obsahuje datové prvky, odpovídající aktuální verzi dat.
		/// Do této položky lze vkládat datové objekty (metodou CarrouselCurrentItem.Set())
		/// anebo z ní objekty číst (metodou CarrouselCurrentItem.Get())
		/// </summary>
		internal DataCarrouselItemCls CarrouselCurrentItem { get { return _CarrouselCurrentItem; } }
		/// <summary> { get; }
		/// Počet položek načtených v karuselu. Indikuje stav načtených dat.
		/// </summary>
		protected int CarrouselCount { get { return this._DataCarrouselDict.Count; } }
		/// <summary>
		/// Najde v karuselu položku pro hledaná data (anebo ji vytvoří jako novou),
		/// a tuto položku umístí do this.CarrouselCurrentItem = aktivní položka.
		/// </summary>
		/// <param name="dataVersion"></param>
		protected void CarrouselSelectItem(int dataVersion)
		{
			if (!this._DataCarrouselDict.ContainsKey(dataVersion))
				this._DataCarrouselDict.Add(dataVersion, DataCarrouselItemCls.Create(dataVersion));
			this._CarrouselCurrentItem = this._DataCarrouselDict[dataVersion];
		}
		/// <summary>
		/// Uloží nynější datové objekty do aktuální položky karuselu (CarrouselCurrentItem).
		/// Virtuální metoda, určená k přepsání.
		/// Měla by se volat v průběhu aktivace verze dat z metody ActivateDataVersion() v její první části 
		///  (kdy ukládám nynější data do položky karuselu this.CurrentPlanCVersion),
		/// a pak by se měla volat z metody DataPrepare(), na jejím úplném konci, když jsou všechna data korektně připravena.
		/// Obsahem metody má být opakované volání this.CarrouselCurrentItem.Set(code, data) pro všechna data, která jsou závislá na verzi.
		/// </summary>
		protected virtual void CarrouselStoreDataToCurrent()
		{ }
		/// <summary>
		/// Zjistí, zda karusel obsahuje položku daného čísla, a vrací true = existuje / false = neexistuje.
		/// </summary>
		/// <param name="dataVersion"></param>
		internal bool CarrouselExists(int dataVersion)
		{
			return this._DataCarrouselDict.ContainsKey(dataVersion);
		}
		/// <summary>
		/// Zjistí, zda karusel obsahuje položku daného čísla, a vrací true = existuje / false = neexistuje.
		/// Pokud existuje, uloží ji do out parametru, ale rozhodně ji neaktivuje do CarrouselCurrentItem.
		/// Pokud neexistuje, pak ji nezakládá.
		/// </summary>
		/// <param name="dataVersion"></param>
		internal bool CarrouselTryGetItem(int dataVersion, out DataCarrouselItemCls item)
		{
			return this._DataCarrouselDict.TryGetValue(dataVersion, out item);
		}
		/// <summary>
		/// Smaže karusel s daty, provádí se při ukončení přístupu k datům jedné databáze (při ukončení, při odpojení)
		/// </summary>
		protected virtual void CarrouselClear()
		{
			foreach (DataCarrouselItemCls item in this._DataCarrouselDict.Values)
				item.Dispose();
			this._DataCarrouselDict.Clear();
			this._DataCarrouselDict = new Dictionary<int, DataCarrouselItemCls>();
		}
        /// <summary>
        /// Vrátí seznam všech položek karuselu z této instance třídy.
        /// </summary>
        /// <returns></returns>
        internal List<DataCarrouselItemCls> CarrouselGetAllItem()
        {
            return new List<DataCarrouselItemCls>(_DataCarrouselDict.Values);
        }
		private Dictionary<int, DataCarrouselItemCls> _DataCarrouselDict;
		private DataCarrouselItemCls _CarrouselCurrentItem;
		#endregion
		#region ŘÍZENÍ INDEXŮ - PŘÍZNAK NUTNOSTI, NASTAVENÍ, OVĚŘENÍ, VYVOLÁNÍ REINDEXOVÁNÍ
		/// <summary>
		/// Příznak stavu, kdy je třeba znovu vytvořit indexy (poté, kdy je do kterékoli datové tabulky vložena nová věta)
		/// </summary>
		protected bool NeedReIndexing = false;
		/// <summary>
		/// Ověří, zda jsou indexy v pořádku, a pokud nejsou tak je znovu vygeneruje.
		/// Ověření je na základě obsahu proměnné this.NeedReIndexing
		/// </summary>
		protected void CheckIndexes()
		{
			if (this.NeedReIndexing)
				CreateIndexes();
		}
		/// <summary>
		/// Metoda určená pro vytvoření interních idnexů podle existujících dat.
		/// Je třeba volat base.CreateIndexes(); kde dojde k nastavení this.NeedReIndexing = false;.
		/// </summary>
		internal virtual void CreateIndexes()
		{
			this.NeedReIndexing = false;
		}
		#endregion
		#region ŘÍDÍCÍ DATA PLÁNOVACÍHO PROCESU - PŘÍSTUP DO SINGLETONU
		/// <summary> { get; set; }
		/// Řídící data plánovacího procesu.
		/// </summary>
        //internal PlanningControlCls PlanningParameters
        //{
        //    get { return PlanningControlCls.Current; }
        //    set { PlanningControlCls.Current = value; }
        //}
		#endregion
		#region COMMON STATIC LIBRARY
		/// <summary>
		/// Sloučí položky ze více seznamů položek daného typu do jedné výsledné Dictionary, na základě jejich klíče RecordNumber.
		/// </summary>
		/// <param name="lists"></param>
		/// <returns></returns>
		public Dictionary<int, T> JoinListsToDictionary<T>(params IEnumerable<T>[] lists)
			where T : IDbRecord
		{
			Dictionary<int, T> result = new Dictionary<int, T>();
			foreach (List<T> list in lists)
			{
				if (list == null) continue;
				foreach (T item in list)
				{
					int recNo = item.RecordNumber;
					if (!result.ContainsKey(recNo))
						result.Add(recNo, item);
				}
			}
			return result;
		}
        /// <summary>
        /// Metoda vrátí kořen zaokrouhlování, který odpovídá zadaným hodnotám.
        /// Pokud na vstupu jsou hodnoty: 1.00, 10.00, atd (celočíselné), pak vrací 0.
        /// Pokud jsou na vstupu desetinné hodnoty, pak vrací číslo odpovídající jejich desetinné části: pro 10.25, 12.00, 16.50 vrací 2 (nejmenší kořen zaokrouhlení z čísla 10.25).
        /// Výsledek lze použít pro zaokrouhlování jiných čísel, při zachování nejmenšího zlomku.
        /// </summary>
        /// <param name="values"></param>
        /// <returns></returns>
        public static int GetRoundRoot(params decimal[] values)
        {
            return GetRoundRoot(((IEnumerable<decimal>)values));
        }
        /// <summary>
        /// Metoda vrátí kořen zaokrouhlování, který odpovídá zadaným hodnotám.
        /// Pokud na vstupu jsou hodnoty: 1.00, 10.00, atd (celočíselné), pak vrací 0.
        /// Pokud jsou na vstupu desetinné hodnoty, pak vrací číslo odpovídající jejich desetinné části: pro 10.25, 12.00, 16.50 vrací 2 (nejmenší kořen zaokrouhlení z čísla 10.25).
        /// Výsledek lze použít pro zaokrouhlování jiných čísel, při zachování nejmenšího zlomku.
        /// </summary>
        /// <param name="values"></param>
        /// <returns></returns>
        public static int GetRoundRoot(IEnumerable<decimal> values)
        {
            int root = 0;
            foreach (decimal value in values)
            {
                if ((value % 1) == 0) continue;    // Urychlení smyčky
                decimal v = Math.Abs(value);
                for (int r = 1; r < 7; r++)
                {
                    if (r > root)                  // Pokud toto číslo má drobnější desetinnou část, zapamatuji si to
                        root = r;
                    v = 10m * v;                   // Hodnota * 10: hledám nejnižší 10-ti násobek výchozí hodnoty (value), jehož desetinná část == 0
                    if ((v % 1) == 0)
                        break;
                }
            }
            return root;
        }
        /// <summary>
        /// Metoda vrátí záznam verze plánu, který je uveden v parametrech plánovacího procesu.
        /// Pokud v parametrech je zadána verze (je uvozená Dv=), pak se ji pokusí najít.
        /// Může být zadána jako číslo (pak se hledá subjekt), a pokud není nalezen záznam, pak se hledá jako reference.
        /// Lze tedy zadat: Dv=STD, nebo Dv="STD/Daj", nebo Dv=123456.
        /// </summary>
        /// <returns></returns>
        public static PlanCVersionHdrCls GetVersionFromParam()
        {
            string errorMessage;
            List<PlanCVersionHdrCls> planVersList = null;
            return GetVersionFromParam(ref planVersList, out errorMessage);
        }
        /// <summary>
        /// Metoda vrátí záznam verze plánu, který je uveden v parametrech plánovacího procesu.
        /// Pokud v parametrech je zadána verze (je uvozená Dv=), pak se ji pokusí najít.
        /// Může být zadána jako číslo (pak se hledá subjekt), a pokud není nalezen záznam, pak se hledá jako reference.
        /// Lze tedy zadat: Dv=STD, nebo Dv="STD/Daj", nebo Dv=123456.
        /// </summary>
        /// <returns></returns>
        public static PlanCVersionHdrCls GetVersionFromParam(out string errorMessage)
        {
            List<PlanCVersionHdrCls> planVersList = null;
            return GetVersionFromParam(ref planVersList, out errorMessage);
        }
        /// <summary>
        /// Metoda vrátí záznam verze plánu, který je uveden v parametrech plánovacího procesu.
        /// Pokud v parametrech je zadána verze (je uvozená Dv=), pak se ji pokusí najít.
        /// Může být zadána jako číslo (pak se hledá subjekt), a pokud není nalezen záznam, pak se hledá jako reference.
        /// Lze tedy zadat: Dv=STD, nebo Dv="STD/Daj", nebo Dv=123456.
        /// </summary>
        /// <returns></returns>
        public static PlanCVersionHdrCls GetVersionFromParam(ref List<PlanCVersionHdrCls> planVersList)
        {
            string errorMessage;
            return GetVersionFromParam(ref planVersList, out errorMessage);
        }
        /// <summary>
        /// Metoda vrátí záznam verze plánu, který je uveden v parametrech plánovacího procesu.
        /// Pokud v parametrech je zadána verze (je uvozená Dv=), pak se ji pokusí najít.
        /// Může být zadána jako číslo (pak se hledá subjekt), a pokud není nalezen záznam, pak se hledá jako reference.
        /// Lze tedy zadat: Dv=STD, nebo Dv="STD/Daj", nebo Dv=123456.
        /// </summary>
        /// <returns></returns>
        public static PlanCVersionHdrCls GetVersionFromParam(ref List<PlanCVersionHdrCls> planVersList, out string errorMessage)
        {
            PlanCVersionHdrCls result = null;
            errorMessage = null;

            string dv = Steward.ParamGet("Dv", true);
            if (String.IsNullOrEmpty(dv))
            {
                errorMessage = MessageInfo.Get("Při spuštění funkce \"Plánovací proces\" nebyl předán záznam třídy \"Kapacitní plán verze\" (parametr Dv=???).");
            }
            else
            {
                if (planVersList == null)
                    planVersList = Db_Layer.GetList<PlanCVersionHdrCls>(PlanCVersionHdrCls.SqlSelect);

                int recordNumber;
                if (Int32.TryParse(dv, out recordNumber))
                    result = planVersList.FirstOrDefault(v => v.RecordNumber == recordNumber);     // Zkusím hledat číslo subjektu

                if (result == null)
                    result = planVersList.FirstOrDefault(v => String.Equals(v.Reference, dv, StringComparison.CurrentCultureIgnoreCase));  // Zkusím hledat referenci

                if (result == null)
                    errorMessage = MessageInfo.Get("Při spuštění funkce \"Plánovací proces\" byl předán požadavek na neexistující záznam třídy \"Kapacitní plán verze\" (parametr Dv=%0).", dv);
            }
            return result;
        }
        #endregion
		#region KONVERZNÍ METODY = PŘEVODY MEZI DATOVÝMI TYPY
		/// <summary>
		/// Metoda vrátí SqlInt32 pro uložení do property představující nepovinný vztah.
		/// Pokud je na vstupu kladná hodnota, vrátí ji (jako SqlInt32).
		/// Pokud je na vstupu nula nebo záporná hodnota, vrátí SqlInt32.Null
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		internal static SqlInt32 Int32ToRelation(int value)
		{
			if (value > 0) return new SqlInt32(value);
			return SqlInt32.Null;
		}
		/// <summary>
		/// Metoda vrátí Int32 pro uložení do property datového objektu, kde 0 představuje null.
		/// Na vstupu je SqlInt32, typický typ pro nepovinný vztah, kde hodnota null představuje žádný vztah.
		/// Zjednodušeně: z null vrací 0, jinak vrací Value.
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		internal static int RelationToInt32(SqlInt32 value)
		{
			return (value.IsNull ? 0 : value.Value);
		}
		/// <summary>
		/// Metoda vrátí SqlInt16 z čísla Int32
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		internal static SqlInt16 Int32ToSqlInt16(int value)
		{
			if (value > (int)(short.MaxValue)) return new SqlInt16(short.MaxValue);
			if (value < (int)(short.MinValue)) return new SqlInt16(short.MinValue);
			return new SqlInt16((short)value);
		}
		/// <summary>
		/// Metoda vrátí SqlDateTime z DateTime
		/// </summary>
		/// <param name="dateTime"></param>
		/// <returns></returns>
		internal static SqlDateTime DateTimeToSqlDateTime(DateTime dateTime)
		{
			if (dateTime < SqlDateTime.MinValue.Value || dateTime > SqlDateTime.MaxValue.Value) return SqlDateTime.Null;
			return new SqlDateTime(dateTime);
		}
		/// <summary>
		/// Metoda vrátí datum tak, aby bylo možno jej vložit do SQL columnu typu DateTime not null.
		/// </summary>
		/// <param name="dateTime">Primární hodnota</param>
		/// <param name="defValues">Sada náhradních hodnot</param>
		/// <returns></returns>
		internal static DateTime DateTimeToDateTimeNotNull(DateTime dateTime, params DateTime[] defValues)
		{
			if (IsDateTimeSqlCompliant(dateTime)) return dateTime;
			if (defValues != null)
			{
				foreach (DateTime defVal in defValues)
				{
					if (IsDateTimeSqlCompliant(defVal)) return defVal;
				}
			}
			return new DateTime(1900, 1, 1);
		}
		/// <summary>
		/// Vrátí true, pokud dané datum je v rozsahu přípustném pro SQL typ Datetime:
		/// January 1, 1753, through December 31, 9999
		/// </summary>
		/// <param name="dateTime"></param>
		/// <returns></returns>
		internal static bool IsDateTimeSqlCompliant(DateTime dateTime)
		{
			return (dateTime >= SQL_DATETIME_MIN && dateTime <= SQL_DATETIME_MAX);
		}
		/// <summary>
		/// Minimální datetime v MSSQL serveru
		/// </summary>
		internal readonly static DateTime SQL_DATETIME_MIN = new DateTime(1753, 1, 1);
		/// <summary>
		/// Maximální datetime v MSSQL serveru
		/// </summary>
		internal readonly static DateTime SQL_DATETIME_MAX = new DateTime(9999, 12, 31, 23, 59, 59);
		/// <summary>
		/// Metoda vrátí číslo fáze (editační styl mfr_operation_phase) na základě fáze (enum OperationPhase)
		/// </summary>
		/// <param name="phase">Výrobní fáze</param>
		/// <returns>Odpovídající číslo</returns>
		internal static SqlInt16 OperationPhaseToSqlInt16(OperationPhase phase)
		{
			switch (phase)
			{
				case OperationPhase.MoveTime:
					return new SqlInt16(1);
				case OperationPhase.TBC:
					return new SqlInt16(2);
				case OperationPhase.TAC:
					return new SqlInt16(3);
				case OperationPhase.TEC:
					return new SqlInt16(4);
			}
			return SqlInt16.Null;
		}
		/// <summary>
		/// Metoda vrátí výrobní fázi (enum OperationPhase) na základě čísla fáze (editační styl mfr_operation_phase)
		/// </summary>
		/// <param name="phase">Číslo výrobní fáze</param>
		/// <returns>Odpovídající fáze</returns>
		internal static OperationPhase SqlInt16ToOperationPhase(SqlInt16 phase)
		{
			if (phase.IsNull) return OperationPhase.None;
			switch (phase.Value)
			{
				case 1:
					return OperationPhase.MoveTime;
				case 2:
					return OperationPhase.TBC;
				case 3:
					return OperationPhase.TAC;
				case 4:
					return OperationPhase.TEC;
			}
			return OperationPhase.None;
		}
		/// <summary>
		/// Metoda vrátí typ kategorie kapacitního zdroje (CapacitySourceCategory)
		/// na základě čísla kategorie zdroje (editační styl mfr_capacity_category : {1=Pracoviště; 2=Profese; 3=Zdroj operace}.
		/// </summary>
		/// <param name="category">Číslo kategorie zdroje kapacit</param>
		/// <returns>Odpovídající kategorie</returns>
		internal static CapacitySourceCategory SqlInt16ToSourceCategory(SqlInt16 category)
		{
			if (category.IsNull) return CapacitySourceCategory.Workplace;
			switch (category.Value)
			{
				case 1:
					return CapacitySourceCategory.Workplace;
				case 2:
					return CapacitySourceCategory.Profession;
				case 3:
					return CapacitySourceCategory.Resource;
			}
			return CapacitySourceCategory.Workplace;
		}
		/// <summary>
		/// Metoda vrátí číslo kategorie zdroje (editační styl mfr_capacity_category : {1=Pracoviště; 2=Profese; 3=Zdroj operace} 
		/// na základě typu kategorie (CapacitySourceCategory).
		/// </summary>
		/// <param name="category">Kategorie zdroje kapacit</param>
		/// <returns>Odpovídající číslo</returns>
		internal static SqlInt16 SourceCategoryToSqlInt16(CapacitySourceCategory category)
		{
			switch (category)
			{
				case CapacitySourceCategory.Workplace:
					return new SqlInt16(1);
				case CapacitySourceCategory.Profession:
					return new SqlInt16(2);
				case CapacitySourceCategory.Resource:
					return new SqlInt16(3);
			}
			return SqlInt16.Null;
		}
		/// <summary>
		/// Z čísla SqlInt16, které je uloženo v DB jako editační styl mfr_oper_fixed, vrátí hodnotu enumu MfrFixedOperationType
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		internal static MfrFixedOperationType SqlInt16ToMfrFixedOperation(SqlInt16 value)
		{
			if (value.IsNull) return MfrFixedOperationType.NotFixed;
			switch (value.Value)
			{
				case 0:
					return MfrFixedOperationType.NotFixed;
				case 1:
					return MfrFixedOperationType.Fixed;
			}
			return MfrFixedOperationType.NotFixed;
		}
		/// <summary>
		/// Z čísla SqlInt16, které je uloženo v DB jako editační styl mfr_oper_fixed, vrátí příznak true, zda je operace fixovaná
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		internal static bool SqlInt16ToIsFixed(SqlInt16 value)
		{
			if (value.IsNull) return false;
			return (value.Value == 1 || value.Value == 2);
		}
		/// <summary>
		/// Z hodnoty enumu MfrFixedOperationType vrátí odpovídající číslo SqlInt16 pro uložení do databáze
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		internal static SqlInt16 MfrFixedOperationToSqlInt16(MfrFixedOperationType value)
		{
			switch (value)
			{
				case MfrFixedOperationType.NotFixed:
					return new SqlInt16(0);
				case MfrFixedOperationType.Fixed:
					return new SqlInt16(1);
			}
			return new SqlInt16(0);
		}
		/// <summary>
		/// Převede příznak fixace (bool : true = operace je fixovaná / false = není) na enum MfrFixedOperationType
		/// </summary>
		/// <param name="isFixed"></param>
		/// <returns></returns>
		internal static MfrFixedOperationType IsFixedToMfrFixed(bool isFixed)
		{
			return (isFixed ? MfrFixedOperationType.Fixed : MfrFixedOperationType.NotFixed);
		}
		/// <summary>
		/// Převede příznak fixace (bool : true = operace je fixovaná / false = není) na enum MfrFixedOperationType
		/// </summary>
		/// <param name="mfrFixed"></param>
		/// <returns></returns>
		internal static bool MfrFixedToIsFixed(MfrFixedOperationType mfrFixed)
		{
			return (mfrFixed == MfrFixedOperationType.Fixed);
		}
		/// <summary>
		/// Vrací Green způsob vzniku záznamu osy S.
		/// Na osu se plní z důvodu zpětné kompatability, ale pro techniku Load and Save se atribut lcs.plan_unit_s_axis.type_rec nepoužívá.
		/// Plánovací tabule využívá atribut lcs.plan_unit_s_axis.change_type.
		/// Proto taky neexistuje zpětná konverzní metoda StringTypeToAxisChangeType(), která by nemohla pracovat korektně
		/// (pro jeden vstupní údaj by mělo existovat více výstupních hodnot).
		/// Namísto toho existuje pár konverzních metod AxisChangeTypeToSqlInt16() a SqlInt16ToAxisChangeType().
		/// <para>Vrací TypeRec: Způsob vzniku záznamu [mfr_mrp_type_rec] 
		/// {"OO"=OO (poptávka); "DO"=DO (objednávka); "PDO"=PDO (potvrzená objednávka); 
		/// "VP"=VP (výrobní příkaz); "KVP"=KVP (komponenty VP); "ROZ"=ROZ (Rozpad); 
		/// "NP"=NP (Návrh příjem); "NV"=NV (Návrh výdej); "MM"=MM (minimum/maximum)}</para>
		/// <para>Db: lcs.plan_unit_s_axis.type_rec (varchar (3) not null)</para>
		/// </summary>
		/// <param name="changeType"></param>
		/// <returns></returns>
		internal static string AxisChangeTypeToStringType(PlanSAxisChangeType changeType)
		{
			switch (changeType)
			{
				case PlanSAxisChangeType.IncrementByRealSupplierOrder:
					return "DO";
				case PlanSAxisChangeType.DecrementByRealEnquiry:
					return "OO";
				case PlanSAxisChangeType.DecrementByPlanEnquiry:
					return "NV";
				case PlanSAxisChangeType.IncrementByPlanSupplierOrder:
					return "NP";
				case PlanSAxisChangeType.IncrementByRealProductOrder:
					return "VP";
				case PlanSAxisChangeType.IncrementByPlanProductOrder:
					return "NP";
				case PlanSAxisChangeType.IncrementByRealByProductSuitable:
					return "VP";
				case PlanSAxisChangeType.IncrementByPlanByProductSuitable:
					return "NP";
				case PlanSAxisChangeType.IncrementByRealByProductDissonant:
					return "VP";
				case PlanSAxisChangeType.IncrementByPlanByProductDissonant:
					return "NP";
                case PlanSAxisChangeType.IncrementByPlanStockTransfer:
                    return "NP";
				case PlanSAxisChangeType.IncrementByProposalReceipt:
					return "NP";
				case PlanSAxisChangeType.DecrementByRealComponent:
					return "KVP";
				case PlanSAxisChangeType.DecrementByPlanComponent:
					return "ROZ";
				case PlanSAxisChangeType.DecrementByProposalRequisition:
					return "NV";
				case PlanSAxisChangeType.IncrementByOrderProduction:
					return "DO";
			}
			return String.Empty;
		}
		/// <summary>
		/// Vrací SqlInt16 hodnotu do Green atributu "Typ změny detailní" na třídě 1180: Plánovací jednotka S osa, editační styl mfr_axis_change_type.
		/// Z typu změny na záznamu osy S vrátí údaj, který se ukládá do databáze.
		/// </summary>
		/// <param name="changeType">Typ změny na záznamu osy v paměti</param>
		/// <returns>Číselná hodnota</returns>
		internal static SqlInt16 AxisChangeTypeToSqlInt16(PlanSAxisChangeType changeType)
		{
			switch (changeType)
			{
				case PlanSAxisChangeType.NotChange:
					return 1;
				case PlanSAxisChangeType.IncrementByRealSupplierOrder:
					return 2;
				case PlanSAxisChangeType.IncrementByPlanSupplierOrder:
					return 3;
				case PlanSAxisChangeType.IncrementByRealProductOrder:
					return 4;
				case PlanSAxisChangeType.IncrementByPlanProductOrder:
					return 5;
				case PlanSAxisChangeType.IncrementByRealByProductSuitable:
					return 6;
				case PlanSAxisChangeType.IncrementByPlanByProductSuitable:
					return 7;
				case PlanSAxisChangeType.IncrementByRealByProductDissonant:
					return 8;
				case PlanSAxisChangeType.IncrementByPlanByProductDissonant:
					return 9;
				case PlanSAxisChangeType.IncrementByProposalReceipt:
					return 10;
				case PlanSAxisChangeType.DecrementByRealEnquiry:
					return 11;
				case PlanSAxisChangeType.DecrementByPlanEnquiry:
					return 12;
				case PlanSAxisChangeType.DecrementByRealComponent:
					return 13;
				case PlanSAxisChangeType.DecrementByPlanComponent:
					return 14;
				case PlanSAxisChangeType.DecrementByProposalRequisition:
					return 15;
				case PlanSAxisChangeType.IncrementByOrderProduction:
					return 16;
                case PlanSAxisChangeType.IncrementByPlanStockTransfer:
                    return 17;
			}
			return 1;
		}
		/// <summary>
		/// Vrací typový "Typ změny detailní" z hodnoty odpovídající editačnímu stylu mfr_axis_change_type.
		/// </summary>
		/// <param name="value">Typ změny na záznamu osy v databázi</param>
		/// <returns>Typová hodnota</returns>
		internal static PlanSAxisChangeType SqlInt16ToAxisChangeType(SqlInt16 value)
		{
			if (value.IsNull) return PlanSAxisChangeType.NotChange;

			switch (value.Value)
			{
				case 1:
					return PlanSAxisChangeType.NotChange;
				case 2:
					return PlanSAxisChangeType.IncrementByRealSupplierOrder;
				case 3:
					return PlanSAxisChangeType.IncrementByPlanSupplierOrder;
				case 4:
					return PlanSAxisChangeType.IncrementByRealProductOrder;
				case 5:
					return PlanSAxisChangeType.IncrementByPlanProductOrder;
				case 6:
					return PlanSAxisChangeType.IncrementByRealByProductSuitable;
				case 7:
					return PlanSAxisChangeType.IncrementByPlanByProductSuitable;
				case 8:
					return PlanSAxisChangeType.IncrementByRealByProductDissonant;
				case 9:
					return PlanSAxisChangeType.IncrementByPlanByProductDissonant;
				case 10:
					return PlanSAxisChangeType.IncrementByProposalReceipt;
				case 11:
					return PlanSAxisChangeType.DecrementByRealEnquiry;
				case 12:
					return PlanSAxisChangeType.DecrementByPlanEnquiry;
				case 13:
					return PlanSAxisChangeType.DecrementByRealComponent;
				case 14:
					return PlanSAxisChangeType.DecrementByPlanComponent;
				case 15:
					return PlanSAxisChangeType.DecrementByProposalRequisition;
				case 16:
					return PlanSAxisChangeType.IncrementByOrderProduction;
                case 17:
                    return PlanSAxisChangeType.IncrementByPlanStockTransfer;
			}
			return PlanSAxisChangeType.NotChange;
		}
		/// <summary>
		/// Vrací SqlInt16 hodnotu do Green atributu "Důvod vzniku záznamu" na třídě 1180: Plánovací jednotka S osa, editační styl mfr_axis_origin_reason.
		/// Z důvodu vzniku na záznamu osy S vrátí údaj, který se ukládá do databáze.
		/// </summary>
		/// <param name="originReason">Důvod vzniku záznamu na záznamu osy v paměti</param>
		/// <returns>Číselná hodnota</returns>
		internal static SqlInt16 AxisOriginReasonToSqlInt16(PlanSAxisOriginReason originReason)
		{
			switch (originReason)
			{
				case PlanSAxisOriginReason.NoReason:
					return 0;
				case PlanSAxisOriginReason.RealRequest:
					return 1;
				case PlanSAxisOriginReason.PlanRequest:
					return 2;
				case (PlanSAxisOriginReason)(PlanSAxisOriginReason.RealRequest | PlanSAxisOriginReason.PlanRequest):
					return 3;
				case PlanSAxisOriginReason.MinimumStock:
					return 4;
				case (PlanSAxisOriginReason)(PlanSAxisOriginReason.RealRequest | PlanSAxisOriginReason.MinimumStock):
					return 5;
				case (PlanSAxisOriginReason)(PlanSAxisOriginReason.PlanRequest | PlanSAxisOriginReason.MinimumStock):
					return 6;
				case (PlanSAxisOriginReason)(PlanSAxisOriginReason.RealRequest | PlanSAxisOriginReason.PlanRequest | PlanSAxisOriginReason.MinimumStock):
					return 7;
			}
			return 0;
		}
		/// <summary>
		/// Vrací typový "Důvod vzniku záznamu" z hodnoty odpovídající editačnímu stylu mfr_axis_origin_reason.
		/// </summary>
		/// <param name="value">Důvod vzniku záznamu záznamu osy S v databázi</param>
		/// <returns>Typová hodnota</returns>
		internal static PlanSAxisOriginReason SqlInt16ToAxisOriginReason(SqlInt16 value)
		{
			if (value.IsNull) return PlanSAxisOriginReason.NoReason;

			switch (value.Value)
			{
				case 0:
					return PlanSAxisOriginReason.NoReason;
				case 1:
					return PlanSAxisOriginReason.RealRequest;
				case 2:
					return PlanSAxisOriginReason.PlanRequest;
				case 3:
					return (PlanSAxisOriginReason)(PlanSAxisOriginReason.RealRequest | PlanSAxisOriginReason.PlanRequest);
				case 4:
					return PlanSAxisOriginReason.MinimumStock;
				case 5:
					return (PlanSAxisOriginReason)(PlanSAxisOriginReason.RealRequest | PlanSAxisOriginReason.MinimumStock);
				case 6:
					return (PlanSAxisOriginReason)(PlanSAxisOriginReason.PlanRequest | PlanSAxisOriginReason.MinimumStock);
				case 7:
					return (PlanSAxisOriginReason)(PlanSAxisOriginReason.RealRequest | PlanSAxisOriginReason.PlanRequest | PlanSAxisOriginReason.MinimumStock);
			}
			return PlanSAxisOriginReason.NoReason;
		}
		/// <summary>
		/// Vrací Green typ dispozice z daného typu změny.
		/// <para>Vrací Type: Typ dispozice [mfr_prj_vyd] {"P"=Příjem; "V"=Výdej}</para><para>Db: lcs.plan_unit_s_axis.type (char (1) not null)</para>
		/// </summary>
		/// <param name="changeType"></param>
		/// <returns></returns>
		internal static string AxisChangeTypeToStringPV(PlanSAxisChangeType changeType)
		{
			decimal coef = AxisChangeTypeToCoefficient(changeType);
			if (coef > 0M) return "P";
			if (coef < 0M) return "V";
			return " ";
		}
		/// <summary>
		/// Určí typ vztahu (RelationType) na základě druhu změny na ose S.
		/// </summary>
		/// <param name="changeType"></param>
		/// <returns></returns>
		internal static PlanningItemRelationType AxisChangeTypeScToRelType(PlanSAxisChangeType changeType)
		{
			switch (changeType)
			{
				case PlanSAxisChangeType.NotChange:
					return PlanningItemRelationType.NotRelation;
				case PlanSAxisChangeType.IncrementByRealSupplierOrder:
				case PlanSAxisChangeType.IncrementByOrderProduction:
				case PlanSAxisChangeType.IncrementByPlanSupplierOrder:
					return PlanningItemRelationType.AxisBalance;
				case PlanSAxisChangeType.IncrementByRealProductOrder:
				case PlanSAxisChangeType.IncrementByPlanProductOrder:
					return PlanningItemRelationType.TaskToAxisFinal;
				case PlanSAxisChangeType.IncrementByRealByProductSuitable:
				case PlanSAxisChangeType.IncrementByPlanByProductSuitable:
					return PlanningItemRelationType.TaskToAxisByProductSuitable;
				case PlanSAxisChangeType.IncrementByRealByProductDissonant:
				case PlanSAxisChangeType.IncrementByPlanByProductDissonant:
					return PlanningItemRelationType.TaskToAxisByProductDissonant;
                case PlanSAxisChangeType.IncrementByPlanStockTransfer:
				case PlanSAxisChangeType.IncrementByProposalReceipt:
					return PlanningItemRelationType.AxisTransfer;
				case PlanSAxisChangeType.DecrementByRealEnquiry:
				case PlanSAxisChangeType.DecrementByPlanEnquiry:
					return PlanningItemRelationType.AxisBalance;
				case PlanSAxisChangeType.DecrementByRealComponent:
				case PlanSAxisChangeType.DecrementByPlanComponent:
					return PlanningItemRelationType.AxisToTask;
				case PlanSAxisChangeType.DecrementByProposalRequisition:
					return PlanningItemRelationType.AxisBalance;
			}
			return PlanningItemRelationType.NotRelation;
		}
        /// <summary>
        /// Vrátí informaci, zda daný druh změny je reálným pohybem, nebo návrhem pohybu.
        /// Vrací true = reálný pohyb / false = návrh
        /// </summary>
        /// <param name="changeType">Typ změny</param>
        /// <returns>true = reálný pohyb / false = návrh</returns>
        internal static bool AxisChangeTypeIsReal(PlanSAxisChangeType changeType)
        {
            switch (changeType)
            {
                case PlanSAxisChangeType.IncrementByRealSupplierOrder:
                case PlanSAxisChangeType.IncrementByOrderProduction:
                case PlanSAxisChangeType.DecrementByRealEnquiry:
                case PlanSAxisChangeType.IncrementByRealProductOrder:
                case PlanSAxisChangeType.DecrementByRealComponent:
                case PlanSAxisChangeType.IncrementByRealByProductSuitable:
                case PlanSAxisChangeType.IncrementByRealByProductDissonant:
                    return true;
                case PlanSAxisChangeType.IncrementByPlanSupplierOrder:
                case PlanSAxisChangeType.IncrementByPlanProductOrder:
                case PlanSAxisChangeType.DecrementByPlanComponent:
                case PlanSAxisChangeType.DecrementByPlanEnquiry:
                case PlanSAxisChangeType.IncrementByPlanStockTransfer:
                case PlanSAxisChangeType.IncrementByProposalReceipt:
                case PlanSAxisChangeType.DecrementByProposalRequisition:
                case PlanSAxisChangeType.IncrementByPlanByProductSuitable:
                case PlanSAxisChangeType.IncrementByPlanByProductDissonant:
                    return false;
            }
            return false;
        }
        
        /// <summary>
        /// Vrátí informaci, zda daný druh změny je plánem, nebo reálným pohybem.
        /// Vrací true = plán (návrhy včetně obchodního plánu) / false = reálný pohyb
        /// </summary>
        /// <param name="changeType">Typ změny</param>
        /// <returns>true = plán (návrhy včetně obchodního plánu) / false = reálný pohyb</returns>
        internal static bool AxisChangeTypeIsPlan(PlanSAxisChangeType changeType)
        {
            switch (changeType)
            {
                case PlanSAxisChangeType.IncrementByRealSupplierOrder:
                case PlanSAxisChangeType.IncrementByOrderProduction:
                case PlanSAxisChangeType.DecrementByRealEnquiry:
                case PlanSAxisChangeType.IncrementByRealProductOrder:
                case PlanSAxisChangeType.DecrementByRealComponent:
                case PlanSAxisChangeType.IncrementByRealByProductSuitable:
                case PlanSAxisChangeType.IncrementByRealByProductDissonant:
                    return false;
                case PlanSAxisChangeType.IncrementByPlanSupplierOrder:
                case PlanSAxisChangeType.IncrementByPlanProductOrder:
                case PlanSAxisChangeType.DecrementByPlanComponent:
                case PlanSAxisChangeType.DecrementByPlanEnquiry:
                case PlanSAxisChangeType.IncrementByPlanStockTransfer:
                case PlanSAxisChangeType.IncrementByProposalReceipt:
                case PlanSAxisChangeType.DecrementByProposalRequisition:
                case PlanSAxisChangeType.IncrementByPlanByProductSuitable:
                case PlanSAxisChangeType.IncrementByPlanByProductDissonant:
                    return true;
            }
            return false;
        }
        /// <summary>
        /// Vrátí informaci, zda daný druh změny je návrhem, který vygeneroval plánovací proces, nebo vstupním pohybem (načtený z vnějších dat).
        /// Vrací true = vygenerovaný návrh / false = vstupující pohyb
        /// </summary>
        /// <param name="changeType">Typ změny</param>
        /// <returns>true = vygenerovaný návrh / false = vstupující pohyb</returns>
        internal static bool AxisChangeTypeIsProposal(PlanSAxisChangeType changeType)
        {
            switch (changeType)
            {
                case PlanSAxisChangeType.IncrementByRealSupplierOrder:
                case PlanSAxisChangeType.IncrementByOrderProduction:
                case PlanSAxisChangeType.DecrementByRealEnquiry:
                case PlanSAxisChangeType.IncrementByRealProductOrder:
                case PlanSAxisChangeType.DecrementByRealComponent:
                case PlanSAxisChangeType.IncrementByRealByProductSuitable:
                case PlanSAxisChangeType.IncrementByRealByProductDissonant:
                    return false;
                case PlanSAxisChangeType.IncrementByPlanSupplierOrder:
                case PlanSAxisChangeType.IncrementByPlanProductOrder:
                case PlanSAxisChangeType.DecrementByPlanComponent:
                    return true;
                case PlanSAxisChangeType.DecrementByPlanEnquiry:       // Poptávka obchodního plánu není vygenerovaný návrh:
                    return false;
                case PlanSAxisChangeType.IncrementByPlanStockTransfer:
                case PlanSAxisChangeType.IncrementByProposalReceipt:
                case PlanSAxisChangeType.DecrementByProposalRequisition:
                case PlanSAxisChangeType.IncrementByPlanByProductSuitable:
                case PlanSAxisChangeType.IncrementByPlanByProductDissonant:
                    return true;
            }
            return false;
        }
        /// <summary>
        /// Vrátí informaci, zda pro daný druh změny se množství ukládá na osu S 
        /// do kolonky "Počet požadováno" (true) anebo "Počet návrh" (false).
        /// </summary>
        /// <param name="changeType">Typ změny</param>
        /// <returns>true = požadavek / false = návrh</returns>
        internal static bool AxisChangeTypeIsToRequestQty(PlanSAxisChangeType changeType)
        {
            switch (changeType)
            {
                case PlanSAxisChangeType.IncrementByRealSupplierOrder:
                case PlanSAxisChangeType.IncrementByOrderProduction:
                case PlanSAxisChangeType.DecrementByRealEnquiry:
                case PlanSAxisChangeType.DecrementByPlanEnquiry:          // Poptávka obchodního plánu je reálný výdej = požadováno.
                case PlanSAxisChangeType.IncrementByRealProductOrder:
                case PlanSAxisChangeType.DecrementByRealComponent:
                case PlanSAxisChangeType.IncrementByRealByProductSuitable:
                case PlanSAxisChangeType.IncrementByRealByProductDissonant:
                    return true;
                case PlanSAxisChangeType.IncrementByPlanSupplierOrder:
                case PlanSAxisChangeType.IncrementByPlanProductOrder:
                case PlanSAxisChangeType.IncrementByPlanStockTransfer:
                case PlanSAxisChangeType.IncrementByProposalReceipt:
                case PlanSAxisChangeType.DecrementByProposalRequisition:
                case PlanSAxisChangeType.IncrementByPlanByProductSuitable:
                case PlanSAxisChangeType.IncrementByPlanByProductDissonant:
                    return false;

                // Od metody IsChangeReal() se liší jen vyhodnocením výdeje do komponenty VP, 
                // kterou zde chápeme jako Požadavek, ne jako Návrh:
                case PlanSAxisChangeType.DecrementByPlanComponent:
                    return true;
            }
            return false;
        }
        /// <summary>
        /// Vrátí informaci, zda daný druh změny je podle skladového dokladu (true) nebo něčeho jiného (false).
        /// </summary>
        /// <param name="changeType">Typ změny</param>
        /// <returns>true = podle skladového dokladu / false = jinak</returns>
        internal static bool AxisChangeTypeIsWarehouseDoc(PlanSAxisChangeType changeType)
        {
            switch (changeType)
            {
                case PlanSAxisChangeType.IncrementByRealSupplierOrder:
                case PlanSAxisChangeType.IncrementByOrderProduction:
                case PlanSAxisChangeType.DecrementByRealEnquiry:
                case PlanSAxisChangeType.DecrementByPlanEnquiry:
                    return true;
                case PlanSAxisChangeType.IncrementByPlanSupplierOrder:
                case PlanSAxisChangeType.IncrementByRealProductOrder:
                case PlanSAxisChangeType.IncrementByPlanProductOrder:
                case PlanSAxisChangeType.IncrementByRealByProductSuitable:
                case PlanSAxisChangeType.IncrementByPlanByProductSuitable:
                case PlanSAxisChangeType.IncrementByRealByProductDissonant:
                case PlanSAxisChangeType.IncrementByPlanByProductDissonant:
                case PlanSAxisChangeType.IncrementByPlanStockTransfer:
                case PlanSAxisChangeType.IncrementByProposalReceipt:
                case PlanSAxisChangeType.DecrementByRealComponent:
                case PlanSAxisChangeType.DecrementByPlanComponent:
                case PlanSAxisChangeType.DecrementByProposalRequisition:
                    return false;
            }
            return false;
        }
        /// <summary>
        /// Vrátí informaci, zda daný druh změny je podle skladového dokladu typu VÝDEJ (reálná poptávka) (true) nebo něčeho jiného (false).
        /// Pokud chceme zjistit, zda jde o poptávku obecně (plán nebo reálná), použije se IsFromAnyWhEnquiry.
        /// </summary>
        /// <param name="changeType">Typ změny</param>
        /// <returns>true = podle skladového dokladu o výdeji do poptávky / false = jinak</returns>
        internal static bool AxisChangeTypeIsFromRealWhEnquiry(PlanSAxisChangeType changeType)
        {
            switch (changeType)
            {
                case PlanSAxisChangeType.IncrementByRealSupplierOrder:
                case PlanSAxisChangeType.IncrementByOrderProduction:
                case PlanSAxisChangeType.DecrementByPlanEnquiry:
                    return false;
                case PlanSAxisChangeType.DecrementByRealEnquiry:
                    return true;
                case PlanSAxisChangeType.IncrementByPlanSupplierOrder:
                case PlanSAxisChangeType.IncrementByRealProductOrder:
                case PlanSAxisChangeType.IncrementByPlanProductOrder:
                case PlanSAxisChangeType.IncrementByRealByProductSuitable:
                case PlanSAxisChangeType.IncrementByPlanByProductSuitable:
                case PlanSAxisChangeType.IncrementByRealByProductDissonant:
                case PlanSAxisChangeType.IncrementByPlanByProductDissonant:
                case PlanSAxisChangeType.IncrementByPlanStockTransfer:
                case PlanSAxisChangeType.IncrementByProposalReceipt:
                case PlanSAxisChangeType.DecrementByRealComponent:
                case PlanSAxisChangeType.DecrementByPlanComponent:
                case PlanSAxisChangeType.DecrementByProposalRequisition:
                    return false;
            }
            return false;
        }
        /// <summary>
        /// Vrátí informaci, zda daný druh změny je podle skladového dokladu typu VÝDEJ (reálná poptávka) (true) nebo něčeho jiného (false).
        /// Pokud chceme zjistit, zda jde o reálnou poptávku (ne o poptávku obchodního plánu), použije se IsFromRealWhEnquiry.
        /// </summary>
        /// <param name="changeType">Typ změny</param>
        /// <returns>true = podle skladového dokladu o výdeji do poptávky / false = jinak</returns>
        internal static bool AxisChangeTypeIsFromAnyWhEnquiry(PlanSAxisChangeType changeType)
        {
            switch (changeType)
            {
                case PlanSAxisChangeType.IncrementByRealSupplierOrder:
                case PlanSAxisChangeType.IncrementByOrderProduction:
                    return false;
                case PlanSAxisChangeType.DecrementByPlanEnquiry:
                case PlanSAxisChangeType.DecrementByRealEnquiry:
                    return true;
                case PlanSAxisChangeType.IncrementByPlanSupplierOrder:
                case PlanSAxisChangeType.IncrementByRealProductOrder:
                case PlanSAxisChangeType.IncrementByPlanProductOrder:
                case PlanSAxisChangeType.IncrementByRealByProductSuitable:
                case PlanSAxisChangeType.IncrementByPlanByProductSuitable:
                case PlanSAxisChangeType.IncrementByRealByProductDissonant:
                case PlanSAxisChangeType.IncrementByPlanByProductDissonant:
                case PlanSAxisChangeType.IncrementByPlanStockTransfer:
                case PlanSAxisChangeType.IncrementByProposalReceipt:
                case PlanSAxisChangeType.DecrementByRealComponent:
                case PlanSAxisChangeType.DecrementByPlanComponent:
                case PlanSAxisChangeType.DecrementByProposalRequisition:
                    return false;
            }
            return false;
        }
        /// <summary>
		/// Vrátí koeficient změny pro daný druh pohybu.
		/// Vrací +1 pro příjmy, -1 pro výdeje. Do příjmu zahrnuje i nepoužitelné vedlejší produkty.
		/// </summary>
		/// <param name="changeType">Typ změny</param>
		/// <returns>+1 pro příjmy, -1 pro výdeje</returns>
		internal static decimal AxisChangeTypeToCoefficient(PlanSAxisChangeType changeType)
		{
			switch (changeType)
			{
				case PlanSAxisChangeType.IncrementByRealSupplierOrder:
				case PlanSAxisChangeType.IncrementByOrderProduction:
				case PlanSAxisChangeType.IncrementByPlanSupplierOrder:
				case PlanSAxisChangeType.IncrementByRealProductOrder:
				case PlanSAxisChangeType.IncrementByPlanProductOrder:
                case PlanSAxisChangeType.IncrementByPlanStockTransfer:
				case PlanSAxisChangeType.IncrementByProposalReceipt:
				case PlanSAxisChangeType.IncrementByRealByProductSuitable:
				case PlanSAxisChangeType.IncrementByPlanByProductSuitable:
				case PlanSAxisChangeType.IncrementByRealByProductDissonant:
				case PlanSAxisChangeType.IncrementByPlanByProductDissonant:
					return 1.0M;
				case PlanSAxisChangeType.DecrementByRealEnquiry:
				case PlanSAxisChangeType.DecrementByPlanEnquiry:
				case PlanSAxisChangeType.DecrementByRealComponent:
				case PlanSAxisChangeType.DecrementByPlanComponent:
				case PlanSAxisChangeType.DecrementByProposalRequisition:
					return -1.0M;
			}
			return 0.0M;
		}
		/// <summary>
		/// Vrátí info o tom, zda daný typ změny pochází z nějakého reálného podkladu (objednávka, poptávka, výrobní příkaz) a ne z návrhu.
		/// Tento záznam fyzicky pochází z podkladového dokladu.
		/// </summary>
		/// <param name="changeType">Typ změny</param>
		/// <returns>true pro příjmy z výroby, false pro výdeje a příjmy jiné než z výroby</returns>
		internal static bool AxisChangeTypeIsFromOriginalRecord(PlanSAxisChangeType changeType)
		{
			switch (changeType)
			{
				case PlanSAxisChangeType.IncrementByRealSupplierOrder:
				case PlanSAxisChangeType.IncrementByOrderProduction:
				case PlanSAxisChangeType.IncrementByRealProductOrder:
				case PlanSAxisChangeType.DecrementByRealEnquiry:
				case PlanSAxisChangeType.DecrementByPlanEnquiry:       // info: poptávka plánu (DecrementByPlanEnquiry) je reálnou existující poptávkou!
					return true;
				case PlanSAxisChangeType.IncrementByPlanSupplierOrder:
				case PlanSAxisChangeType.IncrementByPlanProductOrder:
                case PlanSAxisChangeType.IncrementByPlanStockTransfer:
                case PlanSAxisChangeType.IncrementByProposalReceipt:
				case PlanSAxisChangeType.IncrementByPlanByProductSuitable:
				case PlanSAxisChangeType.IncrementByPlanByProductDissonant:
				case PlanSAxisChangeType.DecrementByRealComponent:     // info: výdej komponenty do reálného VP je na rovině plánu, ne reálného dokladu.
				case PlanSAxisChangeType.IncrementByRealByProductSuitable:    // info: dtto pro příjem vedlejší komponenty, 
				case PlanSAxisChangeType.IncrementByRealByProductDissonant:   //       to není na základě reálného podkladu.
				case PlanSAxisChangeType.DecrementByPlanComponent:
				case PlanSAxisChangeType.DecrementByProposalRequisition:
					return false;
			}
			return false;
		}
		/// <summary>
		/// Vrátí info o tom, zda daný typ změny je příjmem z výroby (true) / jakýkoli jiný záznam (false).
		/// </summary>
		/// <param name="changeType">Typ změny</param>
		/// <returns>true pro příjmy z výroby, false pro výdeje a příjmy jiné než z výroby</returns>
		internal static bool AxisChangeTypeIsReceiptFromProduction(PlanSAxisChangeType changeType)
		{
			switch (changeType)
			{
				case PlanSAxisChangeType.IncrementByOrderProduction:
				case PlanSAxisChangeType.IncrementByRealProductOrder:
				case PlanSAxisChangeType.IncrementByPlanProductOrder:
				case PlanSAxisChangeType.IncrementByRealByProductSuitable:
				case PlanSAxisChangeType.IncrementByPlanByProductSuitable:
				case PlanSAxisChangeType.IncrementByRealByProductDissonant:
				case PlanSAxisChangeType.IncrementByPlanByProductDissonant:
					return true;          // Příjmy z výroby
				case PlanSAxisChangeType.IncrementByRealSupplierOrder:
				case PlanSAxisChangeType.IncrementByPlanSupplierOrder:
                case PlanSAxisChangeType.IncrementByPlanStockTransfer:
				case PlanSAxisChangeType.IncrementByProposalReceipt:
					return false;         // Příjmy mimo výrobu
				case PlanSAxisChangeType.DecrementByRealEnquiry:
				case PlanSAxisChangeType.DecrementByPlanEnquiry:
				case PlanSAxisChangeType.DecrementByRealComponent:
				case PlanSAxisChangeType.DecrementByPlanComponent:
				case PlanSAxisChangeType.DecrementByProposalRequisition:
					return false;         // výdeje
			}
			return false;
		}
		/// <summary>
		/// Vrátí info o tom, zda daný typ změny je příjmem finálního výrobku z výroby (true) / jakýkoli jiný záznam (false).
		/// </summary>
		/// <param name="changeType">Typ změny</param>
		/// <returns>true pro příjmy z výroby, false pro výdeje a příjmy jiné než z výroby</returns>
		internal static bool AxisChangeTypeIsReceiptFinalProduction(PlanSAxisChangeType changeType)
		{
			switch (changeType)
			{
				case PlanSAxisChangeType.IncrementByOrderProduction:
				case PlanSAxisChangeType.IncrementByRealProductOrder:
				case PlanSAxisChangeType.IncrementByPlanProductOrder:
					return true;          // Příjmy z výroby - hlavní produkty
				case PlanSAxisChangeType.IncrementByRealByProductSuitable:
				case PlanSAxisChangeType.IncrementByPlanByProductSuitable:
				case PlanSAxisChangeType.IncrementByRealByProductDissonant:
				case PlanSAxisChangeType.IncrementByPlanByProductDissonant:
					return false;         // Příjmy z výroby - vedlejší produkty
				case PlanSAxisChangeType.IncrementByRealSupplierOrder:
				case PlanSAxisChangeType.IncrementByPlanSupplierOrder:
                case PlanSAxisChangeType.IncrementByPlanStockTransfer:
				case PlanSAxisChangeType.IncrementByProposalReceipt:
					return false;         // Příjmy mimo výrobu
				case PlanSAxisChangeType.DecrementByRealEnquiry:
				case PlanSAxisChangeType.DecrementByPlanEnquiry:
				case PlanSAxisChangeType.DecrementByRealComponent:
				case PlanSAxisChangeType.DecrementByPlanComponent:
				case PlanSAxisChangeType.DecrementByProposalRequisition:
					return false;         // výdeje
			}
			return false;
		}
		/// <summary>
		/// Vrátí info o tom, zda daný typ změny je příjmem vedlejšího výrobku z výroby (true) / jakýkoli jiný záznam (false).
		/// </summary>
		/// <param name="changeType">Typ změny</param>
		/// <returns>true pro příjmy z výroby, false pro výdeje a příjmy jiné než z výroby</returns>
		internal static bool AxisChangeTypeIsReceiptByProduction(PlanSAxisChangeType changeType)
		{
			switch (changeType)
			{
				case PlanSAxisChangeType.IncrementByOrderProduction:
				case PlanSAxisChangeType.IncrementByRealProductOrder:
				case PlanSAxisChangeType.IncrementByPlanProductOrder:
					return false;         // Příjmy z výroby - hlavní produkty
				case PlanSAxisChangeType.IncrementByRealByProductSuitable:
				case PlanSAxisChangeType.IncrementByPlanByProductSuitable:
				case PlanSAxisChangeType.IncrementByRealByProductDissonant:
				case PlanSAxisChangeType.IncrementByPlanByProductDissonant:
					return true;          // Příjmy z výroby - vedlejší produkty
				case PlanSAxisChangeType.IncrementByRealSupplierOrder:
				case PlanSAxisChangeType.IncrementByPlanSupplierOrder:
                case PlanSAxisChangeType.IncrementByPlanStockTransfer:
				case PlanSAxisChangeType.IncrementByProposalReceipt:
					return false;         // Příjmy mimo výrobu
				case PlanSAxisChangeType.DecrementByRealEnquiry:
				case PlanSAxisChangeType.DecrementByPlanEnquiry:
				case PlanSAxisChangeType.DecrementByRealComponent:
				case PlanSAxisChangeType.DecrementByPlanComponent:
				case PlanSAxisChangeType.DecrementByProposalRequisition:
					return false;         // výdeje
			}
			return false;
		}
        /// <summary>
        /// Vrátí info o tom, zda daný typ změny je jakýmkoli příjmem (nehledí se na konkrétní množství, ale na typ záznamu)
        /// </summary>
        /// <param name="changeType">Typ změny</param>
        /// <returns>true pro příjmy, false pro ne příjmy</returns>
        internal static bool AxisChangeTypeIsIncrement(PlanSAxisChangeType changeType)
        {
            switch (changeType)
            {
                case PlanSAxisChangeType.IncrementByOrderProduction:
                case PlanSAxisChangeType.IncrementByRealProductOrder:
                case PlanSAxisChangeType.IncrementByPlanProductOrder:
                case PlanSAxisChangeType.IncrementByRealByProductSuitable:
                case PlanSAxisChangeType.IncrementByPlanByProductSuitable:
                case PlanSAxisChangeType.IncrementByRealByProductDissonant:
                case PlanSAxisChangeType.IncrementByPlanByProductDissonant:
                case PlanSAxisChangeType.IncrementByRealSupplierOrder:
                case PlanSAxisChangeType.IncrementByPlanSupplierOrder:
                case PlanSAxisChangeType.IncrementByPlanStockTransfer:
                case PlanSAxisChangeType.IncrementByProposalReceipt:
                    return true;
                case PlanSAxisChangeType.DecrementByRealEnquiry:
                case PlanSAxisChangeType.DecrementByPlanEnquiry:
                case PlanSAxisChangeType.DecrementByRealComponent:
                case PlanSAxisChangeType.DecrementByPlanComponent:
                case PlanSAxisChangeType.DecrementByProposalRequisition:
                    return false;
            }
            return false;
        }
        /// <summary>
        /// Vrátí info o tom, zda daný typ změny je jakýmkoli výdejem (nehledí se na konkrétní množství, ale na typ záznamu)
        /// </summary>
        /// <param name="changeType">Typ změny</param>
        /// <returns>true pro výdej, false pro ne výdej</returns>
        internal static bool AxisChangeTypeIsDecrement(PlanSAxisChangeType changeType)
        {
            switch (changeType)
            {
                case PlanSAxisChangeType.IncrementByOrderProduction:
                case PlanSAxisChangeType.IncrementByRealProductOrder:
                case PlanSAxisChangeType.IncrementByPlanProductOrder:
                case PlanSAxisChangeType.IncrementByRealByProductSuitable:
                case PlanSAxisChangeType.IncrementByPlanByProductSuitable:
                case PlanSAxisChangeType.IncrementByRealByProductDissonant:
                case PlanSAxisChangeType.IncrementByPlanByProductDissonant:
                case PlanSAxisChangeType.IncrementByRealSupplierOrder:
                case PlanSAxisChangeType.IncrementByPlanSupplierOrder:
                case PlanSAxisChangeType.IncrementByPlanStockTransfer:
                case PlanSAxisChangeType.IncrementByProposalReceipt:
                    return false;
                case PlanSAxisChangeType.DecrementByRealEnquiry:
                case PlanSAxisChangeType.DecrementByPlanEnquiry:
                case PlanSAxisChangeType.DecrementByRealComponent:
                case PlanSAxisChangeType.DecrementByPlanComponent:
                case PlanSAxisChangeType.DecrementByProposalRequisition:
                    return true;
            }
            return false;
        }
        /// <summary>
		/// Vrací kategorii úkolu na základě typu T dokumentace
		/// </summary>
		/// <param name="tDocType"></param>
		/// <returns></returns>
		internal static string TDocTypeToMfrTaskCategory(TDocumentType tDocType)
		{
			switch (tDocType)
			{
				case TDocumentType.Production:
					return "1";
				case TDocumentType.PlanApproved:
					return "2";
				case TDocumentType.PlanPrepared:
					return "3";
			}
			return " ";
		}
		/// <summary>
		/// Vrací typ T dokumentace na základě kategorie úkolu 
		/// </summary>
		/// <param name="tDocType"></param>
		/// <returns></returns>
		internal static TDocumentType MfrTaskCategoryToTDocType(string category)
		{
			switch (category)
			{
				case "1":
					return TDocumentType.Production;
				case "2":
					return TDocumentType.PlanApproved;
				case "3":
					return TDocumentType.PlanPrepared;
			}
			return TDocumentType.PlanApproved;
		}
		#endregion
		#region KONVERZE ENUMŮ NA ČITELNÝ TEXT
		/// <summary>
		/// Vrátí textový název daného typu změny na ose S.
		/// </summary>
		/// <param name="changeType">Typ změny</param>
		/// <returns>Název typu změny</returns>
		internal static string AxisChangeTypeToText(PlanSAxisChangeType changeType)
		{
			switch (changeType)
			{
				case PlanSAxisChangeType.NotChange:
					return "Beze změny";
				case PlanSAxisChangeType.IncrementByRealSupplierOrder:
					return "Zvýšení zásoby příjmem z existující skladové objednávky";
				case PlanSAxisChangeType.IncrementByPlanSupplierOrder:
					return "Zvýšení zásoby příjmem z návrhu skladové objednávky";
				case PlanSAxisChangeType.IncrementByRealProductOrder:
					return "Zvýšení zásoby příjmem z existujícího výrobního příkazu";
				case PlanSAxisChangeType.IncrementByPlanProductOrder:
					return "Zvýšení zásoby příjmem z návrhu výrobního příkazu";
				case PlanSAxisChangeType.IncrementByRealByProductSuitable:
					return "Zvýšení zásoby příjmem z vedlejšího produktu existujícího výrobního příkazu, použitelný materiál/polotovar";
				case PlanSAxisChangeType.IncrementByPlanByProductSuitable:
					return "Zvýšení zásoby příjmem z vedlejšího produktu návrhu výrobního příkazu, použitelný materiál/polotovar";
				case PlanSAxisChangeType.IncrementByRealByProductDissonant:
					return "Zvýšení zásoby příjmem z vedlejšího produktu existujícího výrobního příkazu, nepoužitelný materiál/polotovar";
				case PlanSAxisChangeType.IncrementByPlanByProductDissonant:
					return "Zvýšení zásoby příjmem z vedlejšího produktu návrhu výrobního příkazu, nepoužitelný materiál/polotovar";
				case PlanSAxisChangeType.IncrementByProposalReceipt:
					return "Zvýšení návrhem na příjem";
				case PlanSAxisChangeType.DecrementByRealEnquiry:
					return "Snížení zásoby výdejem do reálné poptávky";
				case PlanSAxisChangeType.DecrementByPlanEnquiry:
					return "Snížení zásoby výdejem do plánované poptávky (obchodní plán)";
				case PlanSAxisChangeType.DecrementByRealComponent:
					return "Snížení zásoby výdejem do komponenty reálného výrobního příkazu";
				case PlanSAxisChangeType.DecrementByPlanComponent:
					return "Snížení zásoby výdejem do komponenty plánovaného výrobního příkazu";
				case PlanSAxisChangeType.DecrementByProposalRequisition:
					return "Snížení zásoby návrhem na výdej do jiného skladu";
				case PlanSAxisChangeType.IncrementByOrderProduction:
					return "Zvýšení zásoby příjmem ze skladové objednávky, zajištěné vlastní výrobou";
                case PlanSAxisChangeType.IncrementByPlanStockTransfer:
                    return "Zvýšení návrhem na příjem z jiného skladu";
            }
			return "[" + changeType.ToString() + "]";
		}
        /// <summary>
        /// Vrátí textový název daného typu změny na ose S.
        /// </summary>
        /// <param name="changeType">Typ změny</param>
        /// <returns>Název typu změny</returns>
        internal static string AxisChangeTypeToTextShort(PlanSAxisChangeType changeType)
        {
            switch (changeType)
            {
                case PlanSAxisChangeType.NotChange:
                    return "Beze změny";
                case PlanSAxisChangeType.IncrementByRealSupplierOrder:
                    return "Příjem z objednávky";
                case PlanSAxisChangeType.IncrementByPlanSupplierOrder:
                    return "Návrh na objednávku";
                case PlanSAxisChangeType.IncrementByRealProductOrder:
                    return "Příjem z výrobního příkazu";
                case PlanSAxisChangeType.IncrementByPlanProductOrder:
                    return "Návrh na výrobní příkaz";
                case PlanSAxisChangeType.IncrementByRealByProductSuitable:
                    return "Vedlejší příjem z výrobního příkazu";
                case PlanSAxisChangeType.IncrementByPlanByProductSuitable:
                    return "Vedlejší příjem z návrhu výrobního příkazu";
                case PlanSAxisChangeType.IncrementByRealByProductDissonant:
                    return "Příjem neshody z výrobního příkazu";
                case PlanSAxisChangeType.IncrementByPlanByProductDissonant:
                    return "Příjem neshody z návrhu výrobního příkazu";
                case PlanSAxisChangeType.IncrementByProposalReceipt:
                    return "Návrh na příjem";
                case PlanSAxisChangeType.DecrementByRealEnquiry:
                    return "Výdej do reálné poptávky";
                case PlanSAxisChangeType.DecrementByPlanEnquiry:
                    return "Výdej do obchodního plánu";
                case PlanSAxisChangeType.DecrementByRealComponent:
                    return "Výdej komponenty výrobního příkazu";
                case PlanSAxisChangeType.DecrementByPlanComponent:
                    return "Návrh na výdej komponenty do výrobního příkazu";
                case PlanSAxisChangeType.DecrementByProposalRequisition:
                    return "Návrh na výdej do jiného skladu";
                case PlanSAxisChangeType.IncrementByOrderProduction:
                    return "Příjem z objednávky z vlastní výroby";
                case PlanSAxisChangeType.IncrementByPlanStockTransfer:
                    return "Návrh příjmu z jiného skladu";
            }
            return "[" + changeType.ToString() + "]";
        }
        #endregion
	}
	/// <summary>
	/// Třída pro evidenci datových objektů (typicky Dictionary s daty a Indexy), které jsou závislé na verzi dat (verze plánu).
	/// Karusel v sobě obsahuje všechny datové objekty jedné verze a jednoho modulu.
	/// Každý modul je samostatná instance, potomek třídy PlanningComponentCls, 
	/// a protože třída PlanningComponentCls poskytuje přístup ke karuselu, tím jej má každý modul (svůj vlastní).
	/// </summary>
	internal class DataCarrouselItemCls : IDisposable
	{
		#region KONSTRUKCE
		private DataCarrouselItemCls(int dataVersion)
		{
			this._DataVersion = dataVersion;
			this._DataStore = new Dictionary<int, object>();
		}
		/// <summary>
		/// Vrátí novou položku karuselu
		/// </summary>
		/// <param name="dataVersion">Číslo verze s daty</param>
		/// <returns>Připravená položka karuselu</returns>
		internal static DataCarrouselItemCls Create(int dataVersion)
		{
			return new DataCarrouselItemCls(dataVersion);
		}
		/// <summary>
		/// Klíč verze s daty
		/// </summary>
		internal int DataVersion { get { return _DataVersion; } }
		private int _DataVersion;
		private Dictionary<int, object> _DataStore;
		/// <summary>
		/// Dispose
		/// </summary>
		public void Dispose()
		{
			List<int> keys = new List<int>(this._DataStore.Keys);     // Nejprve načtu seznam klíčů
			foreach (int key in keys)
				this._DataStore[key] = null;                          // a pak jednotlivě vložím null do položek
			this._DataStore.Clear();
		}
		#endregion
		#region PŘÍSTUP K DATŮM
		/// <summary>
		/// Vrátí požadovanou položku karuselu, anebo vrátí null když neexistuje anebo existuje, ale neodpovídá typově.
		/// Položka karuselu je definovaná číslem (itemType), typicky v modulech je připraven Enum : int, který popisuje používané typy dat.
		/// </summary>
		/// <typeparam name="T">Typ hledaného objektu</typeparam>
		/// <param name="itemType">Klíč hledaného objektu</param>
		/// <returns></returns>
		internal T Get<T>(int itemType) where T : class
		{
			object item;
			if (!this._DataStore.TryGetValue(itemType, out item))
				return null;
			if (!(item is T))
				return null;
			return (item as T);
		}
		/// <summary>
		/// Uloží předaný objekt s daty do karuselu.
		/// Objekt je určen jeho typem (typicky v modulech je připraven Enum : int, který popisuje používané typy dat).
		/// Objekt je předán v parametru (data).
		/// </summary>
		/// <param name="itemType">Klíč hledaného objektu</param>
		/// <param name="data">Objekt s daty</param>
		internal void Set(int itemType, object data)
		{
			if (!this._DataStore.ContainsKey(itemType))
				this._DataStore.Add(itemType, data);
			else
				this._DataStore[itemType] = data;
		}
		#endregion
	}
}
